package dtm

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"gitee.com/xuyiping_admin/pkg/logger/zaplog"
	"gitee.com/xuyiping_admin/pkg/xerr"
	"go.uber.org/zap"
	"gorm.io/gorm"
	"kpt-dtm/model"
	"kpt-dtm/model/dtm"
	"kpt-dtm/service/http"
	"net/url"
	"strconv"
)

const (
	PenCount  = "/api/odata/Pen/$count"
	PensList  = "/api/odata/Pen/$10"
	CreatePen = "/api/odata/Pen"
)

func (s *StoreEntry) CustomPenCount(ctx context.Context, pastureId int64) (string, error) {
	res, err := s.HttpClient.DoGet(fmt.Sprintf("%s%s", s.Cfg.DTMConfig[fmt.Sprintf("%d", pastureId)].CompanyUrl, PenCount), []*http.Header{
		&http.Header{
			Key:   "Authorization",
			Value: fmt.Sprintf("Bearer %s", CompanyTokenValue),
		},
	})
	if err != nil {
		return "0", xerr.WithStack(err)
	}

	response := make([]*dtm.GetPensList, 0)
	if err = json.Unmarshal(res, &response); err != nil {
		return "0", xerr.WithStack(err)
	}
	return string(res), nil
}

func (s *StoreEntry) CustomPenList(ctx context.Context, pastureId int64) ([]*dtm.GetPensList, error) {
	res, err := s.HttpClient.DoGet(fmt.Sprintf("%s%s", s.Cfg.DTMConfig[fmt.Sprintf("%d", pastureId)].CompanyUrl, PensList), []*http.Header{
		&http.Header{
			Key:   "Authorization",
			Value: fmt.Sprintf("Bearer %s", CompanyTokenValue),
		},
	})
	if err != nil {
		return nil, xerr.WithStack(err)
	}

	response := make([]*dtm.GetPensList, 0)
	if err = json.Unmarshal(res, &response); err != nil {
		return nil, xerr.WithStack(err)
	}
	return response, nil
}

func (s *StoreEntry) YynHouseInfoToDtmPen(ctx context.Context, pastureId int64, yConfig *model.YConfig) error {
	res, err := s.SynCowHouseInfo(ctx, yConfig)
	if err != nil {
		return xerr.WithStack(err)
	}
	if res.Status != 1 || res.Content == nil || len(res.Content.CowHouseList) <= 0 {
		return xerr.WithStack(xerr.New("获取数据失败"))
	}
	// 获取到云养牛栏舍数据后，将数据导入dtm
	for _, v := range res.Content.CowHouseList {
		ncows, _ := strconv.ParseFloat(v.CowAmount, 64)
		if 0 == ncows || ncows > 1000 {
			continue
		}
		// 判断栏舍是否存在
		cowBarn := &model.CowBarn{}
		if err = s.DB.Model(new(model.CowBarn)).
			Where("pasture_id = ?", pastureId).
			Where("house_uuid = ?", v.HouseUuid).
			First(cowBarn).Error; err != nil {
			if !errors.Is(err, gorm.ErrRecordNotFound) {
				return xerr.WithStack(err)
			}
		}
		// 存在则判断栏舍名称和数量是否一致
		if cowBarn.Id > 0 && cowBarn.HouseName == v.HouseName && cowBarn.CowNum == v.CowAmount {
			continue
		}

		var (
			dtmPenRes  *dtm.PenValue
			newPenData *dtm.GetPensList
		)

		newPenValue := &dtm.PenValue{
			Name:      v.HouseName,
			Enabled:   true,
			NCows:     int(ncows),
			AdjPerc:   ncows,
			PenRation: make([]*dtm.PenRation, 0),
		}
		// 判断栏舍是否存在，不存在则创建
		if cowBarn.Id <= 0 {
			dtmPenRes, err = s.CreatePen(ctx, newPenValue, pastureId)
			if err != nil {
				return xerr.WithStack(err)
			}
			newCowBarn := model.NewCowBarn(pastureId, v.HouseUuid, v.HouseName, v.CowAmount, dtmPenRes.PenId)
			if err = s.DB.Table(new(model.CowBarn).TableName()).Create(newCowBarn).Error; err != nil {
				return xerr.WithStack(err)
			}
		}

		// 判断栏舍是否存在，存在则更新
		if cowBarn.Id > 0 && (cowBarn.HouseName != v.HouseName || cowBarn.CowNum != v.CowAmount) {
			// 更新栏舍名称和数量
			newPenValue.PenId = cowBarn.PenId
			newPenData, err = s.GetPen(ctx, newPenValue.PenId, pastureId)
			if err != nil {
				continue
			}

			if len(newPenData.Value) <= 0 {
				continue
			}
			newPenValue.LastModify = newPenData.Value[0].LastModify
			newPenValue.RowVersion = newPenData.Value[0].RowVersion

			if err = s.UpdatePen(ctx, newPenValue, newPenValue.PenId, pastureId); err != nil {
				return xerr.WithStack(err)
			}
			if err = s.DB.Table(new(model.CowBarn).TableName()).Where("id = ?", cowBarn.Id).Updates(map[string]interface{}{
				"house_name": v.HouseName,
				"cow_num":    v.CowAmount,
			}).Error; err != nil {
				return xerr.WithStack(err)
			}
		}
	}
	return nil
}

func (s *StoreEntry) CreatePen(ctx context.Context, req *dtm.PenValue, pastureId int64) (*dtm.PenValue, error) {
	res, err := s.HttpClient.DoPost(fmt.Sprintf("%s%s", s.Cfg.DTMConfig[fmt.Sprintf("%d", pastureId)].CompanyUrl, CreatePen), req, []*http.Header{
		&http.Header{
			Key:   "Authorization",
			Value: fmt.Sprintf("Bearer %s", CompanyTokenValue),
		},
	})

	if err != nil {
		zaplog.Error("CreatePen",
			zap.Any("req", req),
			zap.Any("res", string(res)),
			zap.Any("url", CreatePen),
			zap.Any("err", err),
		)
		return nil, xerr.WithStack(err)
	}

	response := &dtm.PenValue{}
	if err = json.Unmarshal(res, response); err != nil {
		return nil, xerr.WithStack(err)
	}
	return response, nil
}

func (s *StoreEntry) UpdatePen(ctx context.Context, req *dtm.PenValue, penId int, pastureId int64) error {
	urlPath := fmt.Sprintf("%s%s%s", s.Cfg.DTMConfig[fmt.Sprintf("%d", pastureId)].CompanyUrl, CreatePen, fmt.Sprintf("/%d?forceRecipeUpdate=null", penId))
	res, err := s.HttpClient.DoPut(urlPath, req, []*http.Header{
		&http.Header{
			Key:   "Authorization",
			Value: fmt.Sprintf("Bearer %s", CompanyTokenValue),
		},
	})
	if err != nil {
		zaplog.Error("UpdatePen", zap.Any("url", urlPath), zap.Any("req", req), zap.Any("res", string(res)), zap.Error(err))
		return xerr.WithStack(err)
	}
	return nil
}

func (s *StoreEntry) GetPen(ctx context.Context, penId int, pastureId int64) (*dtm.GetPensList, error) {
	urlValue := url.Values{}
	urlValue.Add("$filter", fmt.Sprintf("penId eq %d", penId))
	urlPath := fmt.Sprintf("%s%s?%s", s.Cfg.DTMConfig[fmt.Sprintf("%d", pastureId)].CompanyUrl, CreatePen, urlValue.Encode())
	res, err := s.HttpClient.DoGet(urlPath, []*http.Header{
		&http.Header{
			Key:   "Authorization",
			Value: fmt.Sprintf("Bearer %s", CompanyTokenValue),
		},
	})
	if err != nil {
		zaplog.Error("GetPen", zap.Any("url", urlPath), zap.Error(err), zap.Any("CompanyTokenValue", CompanyTokenValue))
		return nil, xerr.WithStack(err)
	}
	response := &dtm.GetPensList{}
	if err = json.Unmarshal(res, response); err != nil {
		return nil, xerr.WithStack(err)
	}
	return response, nil
}
